<?php

namespace App\Http\Controllers\Registry;

use App\Constant;
use App\Enums\PaymentStatus;
use App\Enums\RegistryFileType;
use App\Enums\RegistryStatus;
use App\Enums\SettleWay;
use App\Exceptions\ApiException;
use App\Http\Controllers\Controller;
use App\Models\AgentConfig;
use App\Models\Registry;
use App\Models\RegistryAuditHistory;
use App\Models\RegistryAuth;
use App\Models\RegistryAuthor;
use App\Models\RegistryFile;
use App\Models\RegistryOrder;
use App\Models\RegistryOwner;
use App\Services\AgentService;
use App\Services\RegistryService;
use App\Services\YeepayService;
use Illuminate\Support\Arr;
use Illuminate\Support\Facades\DB;

class RegistryController extends Controller
{
    /** @var RegistryService */
    private $registryService;

    /** @var YeepayService */
    private $yeepayService;

    /** @var AgentService */
    private $agentService;

    /**
     * RegistryController constructor.
     */
    public function __construct(RegistryService $registryService, YeepayService $yeepayService, AgentService $agentService)
    {
        $this->registryService = $registryService;
        $this->yeepayService = $yeepayService;
        $this->agentService = $agentService;
    }

    /** 保存登记信息 */
    public function saveRegistry()
    {
        request()->validate([
            'category' => 'required',
            'creative_nature' => 'required',
            'product_images' => 'nullable | array',
            'create_date' => 'required',
            'create_address' => 'required',
            'is_pub' => 'required',
            'intention' => 'nullable',

            'belong_method' => 'required',
            'belong_explain' => 'nullable',
            'apply_method' => 'required',
            'hold_rights' => 'required | array',
            'hold_explain' => 'nullable',
            'accept_method' => 'required',
            'accept_explain' => 'nullable',
            'author_ids' => 'required | array',
            'owner_ids' => 'required | array',
            'signature' => 'nullable',
            'originality' => 'nullable',
            'attach_files' => 'nullable | array',

            'video_length' => 'nullable',
            'word_count' => 'nullable',
        ]);

        if (request()->id) {
            $registry = $this->findRegistryOrFail(request()->id);
            $isUpdate = true;
            if ($registry->status->is(RegistryStatus::SUBMITTED())) {
                throw new ApiException('审核中的登记信息不可修改');
            }
        } else {
            $registry = new Registry();
            $registry->agent_id = request()->agent_id;
            $registry->user_id = auth()->id();
            $registry->status = RegistryStatus::NOT_PAY();
            $isUpdate = false;
            request()->validate([
                'name' => 'required',
                'product_files' => 'required | array',
            ]);
        }

        /** @var RegistryFile[] $registryFiles */
        $registryFiles = $this->extractRegistryFiles($isUpdate);

        /** @var RegistryAuthor[] $authors */
        $authors = $this->extracAuthors();

        /** @var RegistryOwner[] $owners */
        $owners = $this->extractOwners();

        if (!$isUpdate) {
            $registry->product_name = request()->name;
        }
        $registry->product_create_nat = request()->creative_nature;
        $registry->product_cat = request()->category;
        $registry->product_create_date = request()->create_date;
        $registry->product_create_address = request()->create_address;
        $registry->is_pub = request()->is_pub;
        $registry->create_intention = request()->intention;

        $registry->apply_method = request()->apply_method;
        $registry->accept_method = request()->accept_method;
        $registry->accept_method_explain = request()->accept_explain;
        $registry->belong_method = request()->belong_method;
        $registry->belong_method_explain = request()->belong_explain;
        $registry->hold_names = implode(',', request()->hold_rights);
        $registry->hold_names_explain = request()->hold_explain;
        $registry->originality = request()->originality;
        $registry->signature = request()->signature;
        if (!$isUpdate || $registry->status->is(RegistryStatus::NOT_PAY())) {
            // 新建登记或登记未支付时，根据所选类别重新计算价格
            $registry->pay_amount = toFen($this->getRegistryPrice($registry->product_cat));
        }

        $registry->video_length = request()->video_length;
        $registry->word_count = request()->word_count;

        $registry->settle_way = SettleWay::EVERY_TIME();

        if (request()->is_pub) {
            request()->validate([
                'pub_date' => 'required',
                'pub_address' => 'required',
            ]);
            $registry->product_pub_date = request()->pub_date;
            $registry->product_pub_address = request()->pub_address;
        } else {
            $registry->product_pub_date = null;
            $registry->product_pub_address = null;
        }

        DB::transaction(function () use ($registry, $registryFiles, $authors, $owners) {
            $registry->save();
            // 只更新作品图片和附件，作品文件不可更改
            $registry->productImages()->delete();
            $registry->attachFiles()->delete();
            foreach ($registryFiles as $registryFile) {
                $registryFile->registry_id = $registry->id;
                $registryFile->save();
            }
            $registry->authors()->detach();
            foreach ($authors as $author) {
                $author->registry_id = $registry->id;
                $author->save();
            }
            $registry->owners()->detach();
            foreach ($owners as $owner) {
                $owner->registry_id = $registry->id;
                $owner->save();
            }
        });

        if ($registry->status->isNot(RegistryStatus::NOT_PAY())) {
            if ($registry->register_id) {
                $this->registryService->updateRegistry($registry);
            } else {
                $this->registryService->createRegistry($registry);
            }
        }

        return [
            'id' => $registry->id,
            'need_pay' => $registry->status->is(RegistryStatus::NOT_PAY()),
        ];
    }

    /** 查询登记信息列表 */
    public function listRegistries()
    {
        $page = request()->get('page', 1);
        $limit = request()->get('limit', 5);
        $query = $this->myRegistryQuery()
            ->when(request()->owner_id, function ($q) {
                return $q->whereHas('owners', function ($q1) {
                    return $q1->where('$this->registry_auth_id', request()->owner_id);
                });
            })
            ->when(request()->create_nat, function ($q) {
                return $q->where('product_create_nat', request()->create_nat);
            })
            ->when(request()->belong_method, function ($q) {
                return $q->where('belong_method', request()->belong_method);
            })
            ->when(request()->accept_method, function ($q) {
                return $q->where('accept_method', request()->accept_method);
            })
            ->when(request()->cat_name, function ($q) {
                return $q->where('product_cat', request()->cat_name);
            })
            ->when(request()->start_date, function ($q) {
                return $q->whereDate('created_at', '>=', request()->start_date);
            })
            ->when(request()->end_date, function ($q) {
                return $q->whereDate('created_at', '<=', request()->end_date);
            })
            ->when(request()->keyword, function ($q) {
                return $q->where('product_name', 'like', '%' . request()->keyword . '%');
            })
            ->when(request()->status, function ($q) {
                $statusArr = explode(',', request()->status);

                return $q->whereIn('status', $statusArr);
            });
        $count = $query->count();

        $list = $query
            ->with(['productImages', 'authors', 'owners'])
            ->offset(($page - 1) * $limit)->limit($limit)
            ->orderByDesc('id')->get()
            ->map(function (Registry $registry) {
                $arr = [
                    'id' => $registry->id,
                    'product_name' => $registry->product_name,
                    'create_time' => $registry->created_at->toDateTimeString(),
                    'status' => $registry->status->value,
                    'authors' => $registry->authors->map(function (RegistryAuth $auth) {
                        return $auth->auth_name;
                    }),
                    'owners' => $registry->owners->map(function (RegistryAuth $auth) {
                        return $auth->auth_name;
                    }),
                    'images' => $registry->productImages->map(function (RegistryFile $file) {
                        return $file->file_path;
                    }),
                    'cert_images' => $registry->cert_images,
                    'cert_file' => $registry->cert_file_url,
                ];

                return $arr;
            });

        return [
            'count' => $count,
            'list' => $list,
        ];
    }

    /** 获取登记详情 */
    public function getRegistry($id)
    {
        $registry = $this->findRegistryOrFail($id);
        $registry->load(['authors', 'owners']);

        $arr = [
            // 作品信息
            'name' => $registry->product_name,
            'creative_nature' => $registry->product_create_nat,
            'category' => $registry->product_cat,
            'video_length' => $registry->video_length ?: '',
            'word_count' => $registry->word_count ?: '',
            'product_files' => $registry->productFiles->map(function (RegistryFile $file) {
                return $file->file_path;
            }),
            'product_images' => $registry->productImages->map(function (RegistryFile $file) {
                return $file->file_path;
            }),
            'create_date' => $registry->product_create_date,
            'create_address' => $registry->product_create_address,
            'is_pub' => $registry->is_pub,
            'pub_date' => $registry->is_pub ? $registry->product_pub_date : '',
            'pub_address' => $registry->is_pub ? $registry->product_pub_address : '',
            'intention' => $registry->create_intention ?: '',

            // 权属信息
            'apply_method' => $registry->apply_method,
            'belong_method' => $registry->belong_method,
            'belong_explain' => $registry->belong_method_explain ?: '',
            'hold_rights' => explode(',', $registry->hold_names),
            'hold_names_explain' => $registry->hold_names_explain ?: '',
            'accept_method' => $registry->accept_method,
            'accept_explain' => $registry->accept_method_explain ?: '',
            'authors' => $registry->authors->map(function (RegistryAuth $auth) {
                return [
                    'id' => $auth->id,
                    'auth_name' => $auth->auth_name,
                    'auth_no' => $auth->display_no,
                    'auth_type' => $auth->auth_type->value,
                ];
            })->toArray(),
            'owners' => $registry->owners->map(function (RegistryAuth $auth) {
                return [
                    'id' => $auth->id,
                    'auth_name' => $auth->auth_name,
                    'auth_no' => $auth->display_no,
                    'auth_type' => $auth->auth_type->value,
                ];
            })->toArray(),
            'signature' => $registry->signature ?: '',
            'originality' => $registry->originality ?: '',
            'attach_files' => $registry->attachFiles->map(function (RegistryFile $file) {
                return $file->file_path;
            }),
            'price' => $registry->display_pay_amount,
            'status' => $registry->status->value,
            'register_time' => $registry->created_at->toDateTimeString(),
            'cert_file' => $registry->cert_file_url ?: '',
            'cert_image' => $registry->cert_images,
        ];

        return $arr;
    }

    /** 查询登记支付参数 */
    public function getPaymentParams($id)
    {
        $registry = $this->findRegistryOrFail($id);
        if ($registry->status->isNot(RegistryStatus::NOT_PAY())) {
            throw new ApiException('登记不是未支付状态');
        }
        $order = $registry->order;
        if (!$order) {
            $order = new RegistryOrder();
            $order->registry_id = $registry->id;
        }
        if (!$order->expireTime || now()->gt($order->expireTime)) {
            // 重新下单
            $order->order_id = 'REGISTRY_' . uniqid();

            try {
                $this->yeepayService->setPayNotifyUrl(config('services.yeepay.registry_pay_notify_url'));
                $payLink = $this->yeepayService->getAliQrpayParams(
                    $order->order_id,
                    toYuan($registry->pay_amount),
                    sprintf('【%s】版权登记费用', $registry->product_name)
                );

                $order->payment_params = json_encode(['pay_link' => $payLink]);
                $order->order_no = '';
                $order->save();
            } catch (\Exception $e) {
                throw new ApiException('订单创建失败');
            }
        }

        return json_decode($order->payment_params, true);
    }

    /** 查询登记审核历史 */
    public function listAuditHistories($id)
    {
        $this->findRegistryOrFail($id);

        return RegistryAuditHistory::query()
            ->where('registry_id', $id)
            ->get()
            ->map(function (RegistryAuditHistory $history) {
                return [
                    'type' => $history->type->value,
                    'title' => $history->title,
                    'created_at' => $history->created_at->toDateTimeString(),
                    'remark' => $history->remark ?: '',
                ];
            });
    }

    /** 处理登记审核通知 */
    public function notify()
    {
        request()->validate([
            'registerId' => 'required',
        ]);
        $this->registryService->syncRegistry(request()->registerId);
    }

    /** 处理支付成功通知 */
    public function payNotify()
    {
        $rawData = urldecode(request()->response);
        $data = $this->yeepayService->decryptData($rawData);
        \Log::channel(Constant::LOG_CHANNEL_YEEPAY)->info('REGISTRY_PAY_NOTIFY', $data);
        $orderId = Arr::get($data, 'orderId');
        $status = Arr::get($data, 'status');
        $payDate = Arr::get($data, 'paySuccessDate');

        if ('SUCCESS' === $status) {
            $order = RegistryOrder::query()
                ->where('order_id', $orderId)
                ->first();
            if ($order) {
                $order->pay_time = $payDate;
                $order->pay_status = PaymentStatus::FINISHED();
                $order->save();

                $this->registryService->createRegistry($order->registry);
            }
        }
    }

    private function myRegistryQuery()
    {
        return Registry::query()
            ->where('agent_id', request()->agent_id)
            ->where('user_id', auth()->id());
    }

    private function findRegistryOrFail($id)
    {
        $registry = $this->myRegistryQuery()->find($id);
        if (!$registry) {
            throw new ApiException('无效的的登记ID');
        }

        return $registry;
    }

    /** 处理上传文件 */
    private function extractRegistryFiles($isUpdate = false)
    {
        $params = request()->all();
        $files = [];
        if (!$isUpdate) {
            // 作品文件
            $proFiles = Arr::get($params, 'product_files', []);
            if (0 === count($proFiles)) {
                throw new ApiException('请至少上传一个作品文件');
            }
            foreach ($proFiles as $fileUrl) {
                $ext = Arr::get(pathinfo($fileUrl), 'extension', '');
                if (!RegistryFileType::PRODUCT_IMAGE()->isExtAllowed($ext)) {
                    throw new ApiException('不支持的作品文件扩展名:' . $ext);
                }
                $file = new RegistryFile();
                $file->file_type = RegistryFileType::PRODUCT_FILE;
                $file->file_path = $fileUrl;
                $files[] = $file;
            }
        }
        // 作品图片
        $proImages = Arr::get($params, 'product_images', []);
        foreach ($proImages as $imageUrl) {
            $ext = Arr::get(pathinfo($imageUrl), 'extension', '');
            if (!RegistryFileType::PRODUCT_IMAGE()->isExtAllowed($ext)) {
                throw new ApiException('不支持的作品图片扩展名:' . $ext);
            }
            $file = new RegistryFile();
            $file->file_type = RegistryFileType::PRODUCT_IMAGE;
            $file->file_path = $imageUrl;
            $files[] = $file;
        }

        // 作品附件
        $attachFiles = Arr::get($params, 'attach_files', []);
        foreach ($attachFiles as $fileUrl) {
            $ext = Arr::get(pathinfo($fileUrl), 'extension', '');
            if (!RegistryFileType::PRODUCT_ENCLOSURE()->isExtAllowed($ext)) {
                throw new ApiException('不支持的附件文件扩展名:' . $ext);
            }
            $file = new RegistryFile();
            $file->file_type = RegistryFileType::PRODUCT_ENCLOSURE;
            $file->file_path = $fileUrl;
            $files[] = $file;
        }

        return $files;
    }

    private function extracAuthors()
    {
        $authUsers = RegistryAuth::query()->where('user_id', auth()->id())
            ->get()
            ->mapWithKeys(function (RegistryAuth $auth) {
                return [$auth->id => $auth];
            });
        $authorIds = array_unique(request()->author_ids);
        if (0 === count($authorIds)) {
            throw new ApiException('作者人数不能少于1个');
        }
        if (count($authorIds) > 5) {
            throw new ApiException('作者最多只能添加5个');
        }
        $authors = [];
        foreach ($authorIds as $authorId) {
            if (!Arr::has($authUsers, $authorId)) {
                throw new ApiException('作者信息有误');
            }
            $author = new RegistryAuthor();
            $author->registry_auth_id = $authorId;
            $authors[] = $author;
        }

        return $authors;
    }

    private function extractOwners()
    {
        $authUsers = RegistryAuth::query()->where('user_id', auth()->id())
            ->get()
            ->mapWithKeys(function (RegistryAuth $auth) {
                return [$auth->id => $auth];
            });
        $ownerIds = array_unique(request()->owner_ids);

        if (0 === count($ownerIds)) {
            throw new ApiException('著作权人不能少于1个');
        }
        if (count($ownerIds) > 5) {
            throw new ApiException('著作权人最多只能添加5个');
        }

        $owners = [];
        foreach ($ownerIds as $ownerId) {
            if (!Arr::has($authUsers, $ownerId)) {
                throw new ApiException('著作权人信息有误');
            }

            $owner = new RegistryOwner();
            $owner->registry_auth_id = $ownerId;
            $owners[] = $owner;
        }

        return $owners;
    }

    private function getRegistryPrice($category)
    {
        $priceSettings = $this->agentService->getAgentSettings(request()->agent_id, [
            AgentConfig::REGISTRY_DEFAULT_PRICE,
            AgentConfig::REGISTRY_PRICE_PER_CATEGORY,
        ]);

        $price = Arr::get($priceSettings, AgentConfig::REGISTRY_DEFAULT_PRICE);
        $perCategoryPrice = json_decode(Arr::get($priceSettings, AgentConfig::REGISTRY_PRICE_PER_CATEGORY), true);
        $categoryPrice = Arr::get($perCategoryPrice, $category);
        if ($categoryPrice) {
            $price = $categoryPrice;
        }
        if (empty($price)) {
            throw new ApiException('后台未设置登记价格');
        }

        return $price;
    }
}
